package com.github.cakin.shiro.chapter23.core;

import org.apache.shiro.web.util.SavedRequest;

import javax.servlet.http.HttpServletRequest;

/**
 * @className: ClientSavedRequest
 * @description: 用于 shiro-example-chapter23-app * 模块，当访问一些需要登录的请求时，自动把请求保存下来，
 * 然后重定向到 shiro-example-chapter23-server 模块登录；登录成功后再重定向回来
 * 因为 SavedRequest 不保存 URL 中的 schema://domain:port 部分；所以才需要扩展 SavedRequest；
 * 使得 ClientSavedRequest 能保存 schema://domain:port；这样才能从一个应用重定向另一个（要不然只能在一个应用内重定向）
 * @date: 2020/6/1
 * @author: cakin
 */
public class ClientSavedRequest extends SavedRequest {
    /**
     * 协议名
     */
    private String scheme;
    /**
     * 域
     */
    private String domain;
    /**
     * 端口
     */
    private int port;
    /**
     * 上下文路径
     */
    private String contextPath;
    /**
     * 跳回递增
     */
    private String backUrl;
    /**
     * 80 端口
     */
    private static final int PORT80 = 80;
    /**
     * 443 端口
     */
    private static final int PORT443 = 443;

    public ClientSavedRequest( HttpServletRequest request, String backUrl ) {
        super(request);
        this.scheme = request.getScheme();
        this.domain = request.getServerName();
        this.port = request.getServerPort();
        this.backUrl = backUrl;
        this.contextPath = request.getContextPath();
    }

    public String getScheme() {
        return scheme;
    }

    public String getDomain() {
        return domain;
    }

    public int getPort() {
        return port;
    }

    public String getContextPath() {
        return contextPath;
    }

    public String getBackUrl() {
        return backUrl;
    }

    public String getRequestUrl() {
        String requestURI = getRequestURI();
        if (backUrl != null) {
            // 从外部传入了 backUrl（登录成功之后重定向的地址），且以 http:// 或 https:// 开头那么直接返回
            if (backUrl.toLowerCase().startsWith("http://") || backUrl.toLowerCase().startsWith("https://")) {
                return backUrl;
            } else if (!backUrl.startsWith(contextPath)) { // 如果 backUrl 有值但没有上下文，拼上上下文
                requestURI = contextPath + backUrl;
            } else {
                // 如果 backUrl 有上下文，直接赋值给 requestUrl 即可；
                requestURI = backUrl;
            }
        }
        // 如果 backUrl 没值，那么 requestUrl 就是当前请求的地址
        // 拼上 url 前边的 schema，如 http 或 https
        StringBuilder requestUrl = new StringBuilder(scheme);
        // 拼上域名
        requestUrl.append("://");
        requestUrl.append(domain);
        // 拼上端口
        if ("http".equalsIgnoreCase(scheme) && port != PORT80) {
            requestUrl.append(":").append(String.valueOf(port));
        } else if ("https".equalsIgnoreCase(scheme) && port != PORT443) {
            requestUrl.append(":").append(String.valueOf(port));
        }
        // 拼上重定向到的地址（带上下文）
        requestUrl.append(requestURI);
        // 如果 backUrl 没值，且有查询参数，拼上
        if (backUrl == null && getQueryString() != null) {
            requestUrl.append("?").append(getQueryString());
        }
        // 返回该地址，相应的拦截器直接重定向到它即可
        return requestUrl.toString();
    }
}
